Ext.data.DWRProxy = function(dwrCall, pagingAndSort, args) {
	Ext.data.DWRProxy.superclass.constructor.call(this);
	this.dwrCall = dwrCall;
	this.args = args;
	this.pagingAndSort = (pagingAndSort != undefined ? pagingAndSort : true);
	this.addEvents({
		"loaded" : true
	});
};

Ext.extend(Ext.data.DWRProxy, Ext.data.DataProxy, {
	load : function(params, reader, callback, scope, arg) {
		var sort;
		if (params.sort && params.dir)
			sort = params.sort + ' ' + params.dir;
		else
			sort = '';
		var delegate = this.loadResponse.createDelegate(this, [ reader,
				callback, scope, arg ], 1);
		var callParams = new Array();
		if (this.args) {
			callParams = this.args.slice();
		}
		if (params.args) {
			callParams = callParams.concat(params.args);
		}

		if (this.pagingAndSort) {
			callParams.push(params.start);
			callParams.push(params.limit);
			callParams.push(sort);
		}

		callParams.push(delegate);
		this.dwrCall.apply(this, callParams);
	},

	loadResponse : function(response, reader, callback, scope, arg) {
		var result;
		try {
			result = reader.read(response);
		} catch (e) {
			this.fireEvent("loadexception", this, null, response, e);
			callback.call(scope, null, arg, false);
			return;
		}
		this.fireEvent("load", this, response, this.args);
		callback.call(scope, result, arg, true);
		this.fireEvent("loaded", this, response, this.args);
	},

	update : function(dataSet) {
	},

	updateResponse : function(dataSet) {
	}
});

Ext.data.ListRangeReader = function(meta, recordType) {
	Ext.data.ListRangeReader.superclass.constructor
			.call(this, meta, recordType);
	this.recordType = recordType;
};
Ext
		.extend(
				Ext.data.ListRangeReader,
				Ext.data.DataReader,
				{
					getJsonAccessor : function() {
						var re = /[\[\.]/;
						return function(expr) {
							try {
								return (re.test(expr)) ? new Function("obj",
										"return obj." + expr) : function(obj) {
									return obj[expr];
								};
							} catch (e) {
							}
							return Ext.emptyFn;
						};
					}(),

					read : function(o) {
						var recordType = this.recordType, fields = recordType.prototype.fields;

						// Generate extraction functions for the totalProperty,
						// the root, the id, and for each field
						if (!this.ef) {
							if (this.meta.totalProperty) {
								this.getTotal = this
										.getJsonAccessor(this.meta.totalProperty);
							}

							if (this.meta.successProperty) {
								this.getSuccess = this
										.getJsonAccessor(this.meta.successProperty);
							}

							if (this.meta.id) {
								var g = this.getJsonAccessor(this.meta.id);
								this.getId = function(rec) {
									var r = g(rec);
									return (r === undefined || r === "") ? null
											: r;
								};
							} else {
								this.getId = function() {
									return null;
								};
							}
							this.ef = [];
							for ( var i = 0; i < fields.length; i++) {
								f = fields.items[i];
								var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping
										: f.name;
								this.ef[i] = this.getJsonAccessor(map);
							}
						}

						var records = [];
						var root = o.data, c = root.length, totalRecords = c, success = true;

						if (this.meta.totalProperty) {
							var v = parseInt(this.getTotal(o), 10);
							if (!isNaN(v)) {
								totalRecords = v;
							}
						}

						if (this.meta.successProperty) {
							var v = this.getSuccess(o);
							if (v === false || v === 'false') {
								success = false;
							}
						}

						for ( var i = 0; i < c; i++) {
							var n = root[i];
							var values = {};
							var id = this.getId(n);
							for ( var j = 0; j < fields.length; j++) {
								f = fields.items[j];
								var v = this.ef[j](n);
								values[f.name] = f
										.convert((v !== undefined) ? v
												: f.defaultValue);
							}
							var record = new recordType(values, id);
							records[i] = record;
						}

						return {
							success : success,
							records : records,
							totalRecords : totalRecords
						};
					}
				});

Ext.data.DwrArrayReader = function(meta, recordType) {
	Ext.data.DwrArrayReader.superclass.constructor.call(this, meta, recordType);
	this.recordType = recordType;
};

Ext
		.extend(
				Ext.data.DwrArrayReader,
				Ext.data.DataReader,
				{
					getJsonAccessor : function() {
						var re = /[\[\.]/;
						return function(expr) {
							try {
								return (re.test(expr)) ? new Function("obj",
										"return obj." + expr) : function(obj) {
									return obj[expr];
								};
							} catch (e) {
							}
							return Ext.emptyFn;
						};
					}(),

				    read : function(o){
				        return this.readRecords(o);
				    },

				    readRecords : function(o) {
						var recordType = this.recordType, fields = recordType.prototype.fields;

						// Generate extraction functions for the totalProperty,
						// the root, the id, and for each field
						if (!this.ef) {
							if (this.meta.totalProperty) {
								this.getTotal = this
										.getJsonAccessor(this.meta.totalProperty);
							}

							if (this.meta.successProperty) {
								this.getSuccess = this
										.getJsonAccessor(this.meta.successProperty);
							}

							if (this.meta.id) {
								var g = this.getJsonAccessor(this.meta.id);
								this.getId = function(rec) {
									var r = g(rec);
									return (r === undefined || r === "") ? null
											: r;
								};
							} else {
								this.getId = function() {
									return null;
								};
							}
							this.ef = [];
							for ( var i = 0; i < fields.length; i++) {
								f = fields.items[i];
								var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping
										: f.name;
								this.ef[i] = this.getJsonAccessor(map);
							}
						}

						var records = [];
						var root = o, c = root.length, totalRecords = c, success = true;

						if (this.meta.totalProperty) {
							var v = parseInt(this.getTotal(o), 10);
							if (!isNaN(v)) {
								totalRecords = v;
							}
						}

						if (this.meta.successProperty) {
							var v = this.getSuccess(o);
							if (v === false || v === 'false') {
								success = false;
							}
						}

						for ( var i = 0; i < c; i++) {
							var n = root[i];
							var values = {};
							var id = this.getId(n);
							for ( var j = 0; j < fields.length; j++) {
								f = fields.items[j];
								var v = this.ef[j](n);
								values[f.name] = f
										.convert((v !== undefined) ? v
												: f.defaultValue);
							}
							var record = new recordType(values, id);
							records[i] = record;
						}

						return {
							success : success,
							records : records,
							totalRecords : totalRecords
						};
					}
				});

Ext.data.ListRangeReader = function(meta, recordType) {
	Ext.data.ListRangeReader.superclass.constructor
			.call(this, meta, recordType);
	this.recordType = recordType;
};
Ext
		.extend(
				Ext.data.ListRangeReader,
				Ext.data.DataReader,
				{
					getJsonAccessor : function() {
						var re = /[\[\.]/;
						return function(expr) {
							try {
								return (re.test(expr)) ? new Function("obj",
										"return obj." + expr) : function(obj) {
									return obj[expr];
								};
							} catch (e) {
							}
							return Ext.emptyFn;
						};
					}(),

					read : function(o) {
						var recordType = this.recordType, fields = recordType.prototype.fields;

						// Generate extraction functions for the totalProperty,
						// the root, the id, and for each field
						if (!this.ef) {
							if (this.meta.totalProperty) {
								this.getTotal = this
										.getJsonAccessor(this.meta.totalProperty);
							}

							if (this.meta.successProperty) {
								this.getSuccess = this
										.getJsonAccessor(this.meta.successProperty);
							}

							if (this.meta.id) {
								var g = this.getJsonAccessor(this.meta.id);
								this.getId = function(rec) {
									var r = g(rec);
									return (r === undefined || r === "") ? null
											: r;
								};
							} else {
								this.getId = function() {
									return null;
								};
							}
							this.ef = [];
							for ( var i = 0; i < fields.length; i++) {
								f = fields.items[i];
								var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping
										: f.name;
								this.ef[i] = this.getJsonAccessor(map);
							}
						}

						var records = [];
						var root = o.data, c = root.length, totalRecords = c, success = true;

						if (this.meta.totalProperty) {
							var v = parseInt(this.getTotal(o), 10);
							if (!isNaN(v)) {
								totalRecords = v;
							}
						}

						if (this.meta.successProperty) {
							var v = this.getSuccess(o);
							if (v === false || v === 'false') {
								success = false;
							}
						}

						for ( var i = 0; i < c; i++) {
							var n = root[i];
							var values = {};
							var id = this.getId(n);
							for ( var j = 0; j < fields.length; j++) {
								f = fields.items[j];
								var v = this.ef[j](n);
								values[f.name] = f
										.convert((v !== undefined) ? v
												: f.defaultValue);
							}
							var record = new recordType(values, id);
							records[i] = record;
						}

						return {
							success : success,
							records : records,
							totalRecords : totalRecords
						};
					}
				});

Ext.tree.DWRTreeLoader = function(dwrCall, config, args) {
	Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
	this.dwrCall = dwrCall;
	this.args = args;
};

Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
	load : function(node, callback, scope) {
		if (this.clearOnLoad) {
			while (node.firstChild) {
				node.removeChild(node.firstChild);
			}
		}
		if (this.doPreload(node)) { // preloaded json children
			this.runCallback(callback, scope || node, [ node ]);
		} else if (this.dwrCall) {
			this.requestData(node, callback, scope || node);
		}
	},

    getParams: function(node){
        var bp = Ext.apply({}, this.baseParams),
            np = this.nodeParameter,
            po = this.paramOrder;

        np && (bp[ np ] = node.id);

        if(this.dwrCall){
            var buf = [];
            if(node.args) {
            	buf = node.args.slice();
            }
            buf.push(node.id);
            if(po){
                // reset 'buf' if the nodeParameter was included in paramOrder
                if(np && po.indexOf(np) > -1){
                    buf = [];
                }

                for(var i = 0, len = po.length; i < len; i++){
                    buf.push(bp[ po[i] ]);
                }
            }else if(this.paramsAsHash){
                buf = [bp];
            }
            return buf;
        }else{
            return bp;
        }
    },	
    
	requestData : function(node, callback, scope) {
		if (this.fireEvent("beforeload", this, node, callback) !== false) {
			var callParams = new Array();
			if (this.args) {
				callParams = this.args.slice();
			}
			var params = this.getParams(node);
			if (params) {
				callParams = callParams.concat(params);
			}

			var success = this.handleResponse.createDelegate(this, [ node,
					callback, scope ], 1);
			var error = this.handleFailure.createDelegate(this, [ node,
					callback, scope ], 1);
			//callParams.push(node.id);
			callParams.push({
				callback : success,
				errorHandler : error
			});
			this.transId = true;
			this.dwrCall.apply(this, callParams);
		} else {
			// if the load is cancelled, make sure we notify
			// the node that we are done
			this.runCallback(callback, scope || node, []);
		}
	},

	handleResponse : function(response, node, callback, scope) {
		this.transId = false;
		this.processResponse(response, node, callback, scope);
		this.fireEvent("load", this, node, response);
	},

	handleFailure : function(response, node, callback, scope) {
		this.transId = false;
		this.fireEvent("loadexception", this, node, response);
		this.runCallback(callback, scope || node, [ node ]);
	},

    processResponse : function(response, node, callback, scope){
        try {
            var o = response;
            node.beginUpdate();
            for(var i = 0, len = o.length; i < len; i++){
                var n = this.createNode(o[i]);
                if(n){
                    node.appendChild(n);
                }
            }
            node.endUpdate();
            this.runCallback(callback, scope || node, [node]);
        }catch(e){
            this.handleFailure(response);
        }
    }
});
